package school.valon.test.utils;

import java.math.BigDecimal;
import java.util.Date;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;

import com.owlike.genson.ext.jaxrs.GensonJsonConverter;

import school.valon.constantes.EnumPaymentType;
import school.valon.constantes.EnumStaffFunction;
import school.valon.constantes.EnumUserType;
import school.valon.dto.CourseDto;
import school.valon.dto.CourseOfferingDto;
import school.valon.dto.OutsideDonatorDto;
import school.valon.dto.ParentDto;
import school.valon.dto.PaymentDto;
import school.valon.dto.SchoolPolicyDto;
import school.valon.dto.StaffAttendanceDto;
import school.valon.dto.StaffDto;
import school.valon.dto.StudentClassRecordingDto;
import school.valon.dto.StudentDto;
import school.valon.dto.SurveyAnswerDto;
import school.valon.dto.SurveyQuestionDto;
import school.valon.dto.UserDto;
import school.valon.dto.ValidationRulesDto;

public class Utils {
	public static final String REST_USERS_URL = "http://localhost:8080/web-school/rest/users";
	public static final String REST_COURSES_URL = "http://localhost:8080/web-school/rest/courses";
	public static final String REST_PAYMENTS_URL = "http://localhost:8080/web-school/rest/payments";
	public static final String REST_VALIDATION_RULES_URL = "http://localhost:8080/web-school/rest/validationRules";
	public static final String REST_SCHOOL_POLICIES_URL = "http://localhost:8080/web-school/rest/schoolPolicies";
	public static final String REST_SURVEYS_URL = "http://localhost:8080/web-school/rest/surveys";
	public static final String TEST_ADMIN_EMAIL = "adminTest@valon.com";
	public static final String TEST_ADMIN_PASSWORD = "adminPassTest";
	public static final String TEST_STAFF_EMAIL = "staffTest@valon.com";
	public static final String TEST_STAFF_PASSWORD = "staffPassTest";
	public static final String TEST_PARENT_EMAIL = "parentTest@valon.com";
	public static final String TEST_PARENT_PASSWORD = "parentPassTest";
	public static final String TEST_STUDENT_EMAIL = "studentTest@valon.com";
	public static final String TEST_STUDENT_PASSWORD = "studentPassTest";
	
	private static Utils dummyTestDataCreator;
	private Utils() {}
	public static Utils getInstance() {
		if (dummyTestDataCreator == null) {
			dummyTestDataCreator = new Utils();
			ClientConfig clientConfig = new ClientConfig();
			clientConfig.register(GensonJsonConverter.class);
			dummyTestDataCreator.client = ClientBuilder.newClient(clientConfig);
		}
		return dummyTestDataCreator; 
	}

	private Client client;
	
	public StaffDto createDummyStaff(EnumStaffFunction... functions) {
		WebTarget service = client.target(REST_USERS_URL);
	    service.register(HttpAuthenticationFeature.digest(TEST_STAFF_EMAIL, TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    long time = System.currentTimeMillis();
	    StaffDto userDto = new StaffDto();
	    userDto.setEmail("staffEmailTest" + time);
	    userDto.setFirstName("staffFirstNameTest" + time);
	    userDto.setLastName("staffLastNameTest" + time);
	    userDto.setPassword("staffPasswordTest" + time);
	    userDto.setGender("F");
	    userDto.setEmergencyContact("emergencyContactTest");
	    userDto.setUserType(EnumUserType.STAFF.getUserTypeDto());
	    Response rep = invocationBuilder
	    		.post(Entity.entity(userDto, MediaType.APPLICATION_JSON));
	    StaffDto staffDto = rep.readEntity(StaffDto.class);
	    staffDto.setStaffId(staffDto.getUserId());

	    if (functions == null || functions.length == 0) {
	    	updateStaffRoles(staffDto.getStaffId(), EnumStaffFunction.ADVISOR);
	    } else {
	    	updateStaffRoles(staffDto.getStaffId(), functions);
	    }

	    return staffDto;
	}

	public ParentDto createDummyParent() {
	    WebTarget service = client.target(REST_USERS_URL);
	    service.register(HttpAuthenticationFeature.digest(TEST_STAFF_EMAIL, TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    long time = System.currentTimeMillis();
	    ParentDto userDto = new ParentDto();
	    userDto.setEmail("parentEmailTest" + time);
	    userDto.setFirstName("parentFirstNameTest" + time);
	    userDto.setLastName("parentLastNameTest" + time);
	    userDto.setPassword("parentPasswordTest" + time);
	    userDto.setGender("M");
	    userDto.setEmergencyContact("emergencyContactTest");
	    userDto.setUserType(EnumUserType.PARENT.getUserTypeDto());
	    Response rep = invocationBuilder
	    		.post(Entity.entity(userDto, MediaType.APPLICATION_JSON));
	    ParentDto parentDto = rep.readEntity(ParentDto.class);
	    parentDto.setParentId(parentDto.getUserId());
	    return parentDto;
	}

	public StudentDto createDummyStudent() {
	    WebTarget service = client.target(REST_USERS_URL);
	    service.register(HttpAuthenticationFeature.digest(TEST_STAFF_EMAIL, TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    long time = System.currentTimeMillis();
	    StudentDto userDto = new StudentDto();
	    userDto.setEmail("studentEmailTest" + time);
	    userDto.setFirstName("studentFirstNameTest" + time);
	    userDto.setLastName("studentLastNameTest" + time);
	    userDto.setPassword("studentPasswordTest" + time);
	    userDto.setGender("M");
	    userDto.setEmergencyContact("emergencyContactTest");
	    userDto.setUserType(EnumUserType.STUDENT.getUserTypeDto());
	    userDto.setBirthDate(new Date(System.currentTimeMillis() - 1000 * 3600 * 24 * 365 * 11));
	    Response rep = invocationBuilder
	    		.post(Entity.entity(userDto, MediaType.APPLICATION_JSON));
	    StudentDto studentDto = rep.readEntity(StudentDto.class);
	    studentDto.setStudentId(studentDto.getUserId());
	    return studentDto;
	}

	public OutsideDonatorDto createDummyOutsideDonator() {
	    WebTarget service = client.target(REST_USERS_URL);
	    service.register(HttpAuthenticationFeature.digest(TEST_STAFF_EMAIL, TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    long time = System.currentTimeMillis();
	    OutsideDonatorDto userDto = new OutsideDonatorDto();
	    userDto.setEmail("OutsideDonatorEmailTest" + time);
	    userDto.setFirstName("OutsideDonatorFirstNameTest" + time);
	    userDto.setLastName("OutsideDonatorLastNameTest" + time);
	    userDto.setPassword("OutsideDonatorDtoPasswordTest" + time);
	    userDto.setGender("M");
	    userDto.setEmergencyContact("emergencyContactTest" + time);
	    userDto.setUserType(EnumUserType.OUTSIDE_DONATOR.getUserTypeDto());
	    Response rep = invocationBuilder
	    		.post(Entity.entity(userDto, MediaType.APPLICATION_JSON));
	    OutsideDonatorDto outsideDonatorDto = rep.readEntity(OutsideDonatorDto.class);
	    outsideDonatorDto.setOutsideDonatorId(outsideDonatorDto.getUserId());
	    return outsideDonatorDto;
	}

	public PaymentDto createDummyPayment() {
	    WebTarget service = client.target(REST_PAYMENTS_URL);
	    service.register(HttpAuthenticationFeature.digest(TEST_STAFF_EMAIL, TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    PaymentDto paymentDto = new PaymentDto();
	    paymentDto.setPaidOn(new Date());
	    paymentDto.setAmount(new BigDecimal(666.55));
	    paymentDto.setPaymentType(EnumPaymentType.CASH.getPaymentTypeDto());

	    UserDto userDto = Utils.getInstance().createDummyParent();
	    paymentDto.setUser(userDto);

	    Response rep = invocationBuilder
	    		.post(Entity.entity(paymentDto, MediaType.APPLICATION_JSON));
	    return rep.readEntity(PaymentDto.class);
	}

	public ValidationRulesDto createDummyValidationRules() {
	    WebTarget service = client.target(REST_VALIDATION_RULES_URL);
	    service.register(HttpAuthenticationFeature.digest(TEST_STAFF_EMAIL, TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    ValidationRulesDto validationRulesDto = new ValidationRulesDto();
	    validationRulesDto.setStartDate(new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 5));
	    validationRulesDto.setEndDate(new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 30));
	    validationRulesDto.setCreatedOn(new Date());
	    validationRulesDto.setValue("valueTest");
	    validationRulesDto.setPredefinedRules("predefinedRulesTest");

	    validationRulesDto.setStaff(Utils.getInstance().createDummyStaff());
	    Response rep = invocationBuilder
	    		.post(Entity.entity(validationRulesDto, MediaType.APPLICATION_JSON));
	    return rep.readEntity(ValidationRulesDto.class);
	}

	public SchoolPolicyDto createSchoolPolicy() {
	    WebTarget service = client.target(Utils.REST_SCHOOL_POLICIES_URL);
	    service.register(HttpAuthenticationFeature.digest(Utils.TEST_STAFF_EMAIL, Utils.TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    SchoolPolicyDto schoolPolicyDto = new SchoolPolicyDto();
	    schoolPolicyDto.setCreatedOn(new Date());
	    schoolPolicyDto.setItem("itemTest");
	    schoolPolicyDto.setItemDetails("itemTestDetails");
	    schoolPolicyDto.setStaff(Utils.getInstance().createDummyStaff());

	    Response rep = invocationBuilder
	    		.post(Entity.entity(schoolPolicyDto, MediaType.APPLICATION_JSON));
	    return rep.readEntity(SchoolPolicyDto.class);
	}

	public SurveyQuestionDto createDummySurveyQuestion() {
	    WebTarget service = client.target(Utils.REST_SURVEYS_URL).path("questions");
	    service.register(HttpAuthenticationFeature.digest(Utils.TEST_STAFF_EMAIL, Utils.TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    SurveyQuestionDto surveyQuestionDto = new SurveyQuestionDto();
	    surveyQuestionDto.setCreatedOn(new Date());
	    surveyQuestionDto.setStartDate(new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 2));
	    surveyQuestionDto.setEndDate(new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 10));
	    surveyQuestionDto.setSurveyQuestionName("testSurveyQuestionName");
	    surveyQuestionDto.setSurveyQuestionText("testSurveyQuestionText");
	    surveyQuestionDto.setStaff(Utils.getInstance().createDummyStaff());

	    Response rep = invocationBuilder
	    		.post(Entity.entity(surveyQuestionDto, MediaType.APPLICATION_JSON));
	    return rep.readEntity(SurveyQuestionDto.class);
	}

	public SurveyAnswerDto createDummySurveyAnswer() {
	    WebTarget service = client.target(Utils.REST_SURVEYS_URL).path("/anwsers");
	    service.register(HttpAuthenticationFeature.digest(Utils.TEST_STAFF_EMAIL, Utils.TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);

	    SurveyAnswerDto surveyAnswerDto = new SurveyAnswerDto();
	    surveyAnswerDto.setSurveyAnswer("testSurveyAnswer");
	    surveyAnswerDto.setSurveyAnswerDate(new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 2));
	    surveyAnswerDto.setSurveyQuestion(Utils.getInstance().createDummySurveyQuestion());
	    surveyAnswerDto.setUser(Utils.getInstance().createDummyParent());

	    Response rep = invocationBuilder
	    		.post(Entity.entity(surveyAnswerDto, MediaType.APPLICATION_JSON));

	    return rep.readEntity(SurveyAnswerDto.class);
	}

	public StaffAttendanceDto createDummyStaffAttendance() {
		WebTarget service = client.target(Utils.REST_USERS_URL);
		service.register(HttpAuthenticationFeature.digest(Utils.TEST_STAFF_EMAIL, Utils.TEST_STAFF_PASSWORD));
		Integer teacherId = Utils.getInstance().createDummyStaff(EnumStaffFunction.TEACHER).getUserId();
	    Invocation.Builder invocationBuilder =
	    		service.path("staffs/" + teacherId.toString() + "/attendances")
	    		.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    StaffAttendanceDto staffAttendanceDto = new StaffAttendanceDto();
	    staffAttendanceDto.setAttendanceDate(new Date());
	    staffAttendanceDto.setAttendedHours(new BigDecimal(3));

	    Response rep = invocationBuilder
	    		.post(Entity.entity(staffAttendanceDto, MediaType.APPLICATION_JSON));

	    return rep.readEntity(StaffAttendanceDto.class);
	}

	public CourseDto createDummyCourse() {
	    WebTarget service = client.target(Utils.REST_COURSES_URL);
	    service.register(HttpAuthenticationFeature.digest(Utils.TEST_ADMIN_EMAIL, Utils.TEST_ADMIN_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);

	    CourseDto courseDto = new CourseDto();
	    courseDto.setCourseName("Math course test");
	    courseDto.setCourseDescription("Description course test");
	    courseDto.setFiles(null);

	    Response rep = invocationBuilder
	    		.post(Entity.entity(courseDto, MediaType.APPLICATION_JSON));

	    return rep.readEntity(CourseDto.class);
	}

	public CourseOfferingDto createDummyCourseOffering() {
		WebTarget service = client.target(Utils.REST_COURSES_URL);
		service.register(HttpAuthenticationFeature.digest(Utils.TEST_ADMIN_EMAIL, Utils.TEST_ADMIN_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.path("offerings")
	    		.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    CourseOfferingDto courseOfferingDto = new CourseOfferingDto();
	    courseOfferingDto.setCourse(Utils.getInstance().createDummyCourse());
	    courseOfferingDto.setStaff(Utils.getInstance().createDummyStaff());
	    courseOfferingDto.setStartDate(new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 5));
	    courseOfferingDto.setEndDate(new Date(System.currentTimeMillis() + 1000 * 3600 * 24 * 30));

	    Response rep = invocationBuilder
	    		.post(Entity.entity(courseOfferingDto, MediaType.APPLICATION_JSON));
	    courseOfferingDto = rep.readEntity(CourseOfferingDto.class);
	    return courseOfferingDto;
	}

	public StudentClassRecordingDto createDummyStudentClassRecording() {
		WebTarget service = client.target(Utils.REST_COURSES_URL);
		service.register(HttpAuthenticationFeature.digest(Utils.TEST_STAFF_EMAIL, Utils.TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.path("studentClassRecordings")
	    		.request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
	    StudentClassRecordingDto stdClassRecDto = new StudentClassRecordingDto();
	    stdClassRecDto.setCourseOffering(Utils.getInstance().createDummyCourseOffering());
	    stdClassRecDto.setStudent(Utils.getInstance().createDummyStudent());
	    stdClassRecDto.setClassDate(new Date());
	    stdClassRecDto.setPerformanceMark(BigDecimal.valueOf(20));
	    stdClassRecDto.setAttendedHours(7);

	    Response rep = invocationBuilder
	    		.post(Entity.entity(stdClassRecDto, MediaType.APPLICATION_JSON));
	    return rep.readEntity(StudentClassRecordingDto.class);
	}

	public void updateStaffRoles(Integer staffId, EnumStaffFunction ...functions) {
		WebTarget service = client.target(REST_USERS_URL);
	    service.register(HttpAuthenticationFeature.digest(TEST_STAFF_EMAIL, TEST_STAFF_PASSWORD));
	    Invocation.Builder invocationBuilder =
	    		service.path("teachers").path(staffId.toString()).path("roles")
	    		.request(MediaType.TEXT_PLAIN).accept(MediaType.APPLICATION_JSON);

	    Response rep = invocationBuilder
	    		.put(Entity.entity(functions, MediaType.APPLICATION_JSON));

	    System.out.println(rep.getStatus() + " : " + rep.readEntity(String.class));
	}

}
